﻿/* 
This file is part of Ingo Karstein's Excel Export project

**Do not remove this comment**

Please see the project homepage at CodePlex:
  http://spexcelexport.codeplex.com/

Please see my blog:
  http://ikarstein.wordpress.com

Licence: GPLv2
    Ingo Karstein's SharePoint 2010 Custom Ribbon Demo
    Copyright (C) 2011  Ingo Karstein, ikarstein@hotmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Xml;
using System.IO;
using System.Diagnostics;
using System.Globalization;

namespace ik.SharePoint2010.ExcelExport.Code
{
    internal class ExportToXml
    {
        internal class KeyValue
        {
            public string Key;
            public string Value;

            public KeyValue()
            {
                Key = string.Empty;
                Value = string.Empty;
            }
        }

        private class FieldInfo
        {
            public string internalName;
            public string displayName;
            public int lcid = CultureInfo.CurrentUICulture.LCID;
            public string type;
        }


        public ExportToXml()
        {
        }

        public static string Export(SPList list, Guid view, string url, string listParams, string listQuery)
        {
            if( list == null )
                return "";

            SPView v = list.Views[view];
            if( v == null )
                return "";

            Uri uri = new Uri(url);
            string query = uri.GetComponents(UriComponents.Query, UriFormat.Unescaped);
            SortedList<int, KeyValue> filterfields = new SortedList<int, KeyValue>();
            KeyValue SortField = new KeyValue();
            if( !string.IsNullOrEmpty(query) )
            {
                string[] uriparams = query.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
                foreach( string p in uriparams )
                {
                    string[] kv = p.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                    if( kv.Length == 2 )
                    {
                        if( kv[0].StartsWith("FilterField", StringComparison.InvariantCultureIgnoreCase) )
                        {
                            string num = kv[0].Substring(11);
                            int numInt = 0;
                            if( int.TryParse(num, out numInt) )
                            {
                                if( filterfields.ContainsKey(numInt) )
                                {
                                    filterfields[numInt].Key = kv[1];
                                }
                                else
                                {
                                    KeyValue kv2 = new KeyValue();
                                    kv2.Key = kv[1];
                                    filterfields.Add(numInt, kv2);
                                };
                            }
                        }
                        else if( kv[0].StartsWith("FilterValue", StringComparison.InvariantCultureIgnoreCase) )
                        {
                            string num = kv[0].Substring(11);
                            int numInt = 0;
                            if( int.TryParse(num, out numInt) )
                            {
                                if( filterfields.ContainsKey(numInt) )
                                {
                                    filterfields[numInt].Value = kv[1];
                                }
                                else
                                {
                                    KeyValue kv2 = new KeyValue();
                                    kv2.Value = kv[1];
                                    filterfields.Add(numInt, kv2);
                                };
                            }
                        }
                        else if( kv[0].StartsWith("SortField", StringComparison.InvariantCultureIgnoreCase) )
                        {
                            SortField.Key = kv[1];
                        }
                        else if( kv[0].StartsWith("SortDir", StringComparison.InvariantCultureIgnoreCase) )
                        {
                            SortField.Value = kv[1];
                        }
                    }
                }
            }

            StringBuilder sb = new StringBuilder();

            sb.Append("<splist ");
            sb.Append(@"name=""" + list.ID.ToString() + @""" ");
            sb.Append(@"url=""" + list.DefaultViewUrl.ToString() + @""" ");
            sb.AppendLine(@">");

            SortedList<string, Guid> fieldsToExport = new SortedList<string, Guid>();
            SortedList<string, int> languages = new SortedList<string, int>();

            List<string> hideFields = new List<string>();

            if( !string.IsNullOrEmpty(listParams) )
            {
                XmlDocument xd = new XmlDocument();
                xd.LoadXml(listParams);

                sb.AppendLine(@"<rowfields>");
                XmlNode rowfields = xd.SelectSingleNode("/List/RowFields");
                if( rowfields != null )
                {
                    foreach( XmlNode n in rowfields.ChildNodes )
                    {
                        sb.AppendLine(@"<field internalName=""" + n.Attributes["internalName"].Value + @"""/>");
                    };

                };
                sb.AppendLine(@"</rowfields>");

                XmlNode hidefields = xd.SelectSingleNode("/List/HideFields");
                if( hidefields != null )
                {
                    foreach( XmlNode n in hidefields.ChildNodes )
                    {
                        string fieldName = n.Attributes["internalName"].Value;
                        if( !hideFields.Contains(fieldName) )
                            hideFields.Add(fieldName);
                    }
                };
            }
            else
            {
                sb.AppendLine(@"<rowfields/>");
            }

            SortedList<string, FieldInfo> fields = new SortedList<string, FieldInfo>();

            sb.AppendLine(@"<fields>");
            foreach( string s in v.ViewFields )
            {
                SPField f = list.Fields.GetFieldByInternalName(s);

                FieldInfo fi = new FieldInfo();
                fi.displayName = f.Title;
                fi.internalName = f.InternalName;
                fi.type = f.TypeAsString;
                fields.Add(fi.internalName.ToLower(), fi);

                if( hideFields.Contains(s) )
                    continue;

                sb.Append(@"<field ");
                sb.Append(@"internalName=""" + f.InternalName + @""" ");
                sb.Append(@"displayName=""" + f.Title + @""" ");
                sb.Append(@"type=""" + f.TypeAsString + @""" ");
                XmlDocument schema = new XmlDocument();
                schema.LoadXml(f.SchemaXml);
                if( schema.DocumentElement.Attributes["LCID"] != null )
                {
                    sb.Append(@"lcid=""" + schema.DocumentElement.Attributes["LCID"].Value + @""" ");
                    languages.Add(f.InternalName, int.Parse(schema.DocumentElement.Attributes["LCID"].Value));
                }
                else
                {
                    sb.Append(@"lcid=""" + SPContext.Current.Web.Language.ToString() + @""" ");
                    languages.Add(f.InternalName, (int)SPContext.Current.Web.Language);
                }
                sb.AppendLine(@"/>");
                fieldsToExport.Add(f.InternalName, f.Id);
            }

            sb.AppendLine(@"</fields>");

            List<int> forDeletation = new List<int>();

            sb.AppendLine("<filters>");
            foreach( KeyValuePair<int, KeyValue> kv in filterfields )
            {
                if( !string.IsNullOrEmpty(kv.Value.Key) && !string.IsNullOrEmpty(kv.Value.Value) && fields.ContainsKey(kv.Value.Key.ToLower()) )
                    sb.AppendLine(string.Format(@"<filter field=""{0}"" value=""{1}""/>", kv.Value.Key, kv.Value.Value));
                else
                    forDeletation.Add(kv.Key);
            };

            foreach( var key in forDeletation )
                filterfields.Remove(key);

            sb.AppendLine("</filters>");

            if( !string.IsNullOrEmpty(SortField.Key) && !string.IsNullOrEmpty(SortField.Value) && fields.ContainsKey(SortField.Key.ToLower()) )
            {
                sb.AppendLine("<sorting>");
                sb.AppendLine(string.Format(@"<sort field=""{0}"" type=""{1}""/>", SortField.Key, SortField.Value));
                sb.AppendLine("</sorting>");
            }
            else
                SortField = new KeyValue();

            sb.AppendLine(@"<rows>");

            SPListItemCollection listItems = null;

            //Debugger.Break();

            if( filterfields.Count > 0 || !string.IsNullOrEmpty(SortField.Key) )
            {
                StringBuilder querySb = new StringBuilder();
                querySb.Append("<Where>");
                if( filterfields.Count > 1 )
                    querySb.Append("<And>");
                foreach( KeyValuePair<int, KeyValue> kv in filterfields )
                {
                    if( !string.IsNullOrEmpty(kv.Value.Key) && !string.IsNullOrEmpty(kv.Value.Value) && fields.ContainsKey(kv.Value.Key.ToLower()) )
                    {
                        querySb.Append("<Eq>");
                        querySb.Append("<FieldRef Name=\"" + kv.Value.Key + "\"/>");
                        //querySb.Append("<Value Type=\"" + fields[kv.Value.Key.ToLower()].type +"\" ");
                        //if(string.Compare(fields[kv.Value.Key.ToLower()].type, "datetime", true) == 0)
                        //    querySb.Append(" IncludeTimeValue=\"FALSE\" ");
                        //querySb.Append(">");
                        querySb.Append("<Value Type=\"Text\">");
                        querySb.Append(kv.Value.Value);
                        querySb.Append("</Value>");
                        querySb.Append("</Eq>");
                    }
                };
                if( filterfields.Count > 1 )
                    querySb.Append("</And>");
                querySb.Append("</Where>");

                if( !string.IsNullOrEmpty(SortField.Key) && fields.ContainsKey(SortField.Key.ToLower()) )
                {
                    querySb.Append("<OrderBy>");
                    querySb.Append("<FieldRef Name=\"" + SortField.Key + "\" ");
                    if( SortField.Value.StartsWith("D", StringComparison.InvariantCultureIgnoreCase) )
                        querySb.Append("Ascending=\"False\" />");
                    else
                        querySb.Append("Ascending=\"True\" />");
                    querySb.Append("</OrderBy>");
                }

                SPQuery q = new SPQuery();
                q.Query = querySb.ToString();
               
                listItems = list.GetItems(q);
            }
            else
                listItems = list.Items;

            foreach( SPListItem li in listItems )
            {
                sb.AppendLine(@"<row>");
                foreach( KeyValuePair<string, Guid> s in fieldsToExport )
                {
                    if( hideFields.Contains(s.Key) )
                        continue;

                    sb.Append(@"<field ");
                    sb.Append(@"internalName=""" + s.Key + @""" ");
                    sb.Append(@">");
                    try
                    {
                        CultureInfo ci = new CultureInfo(languages[s.Key]);

                        if( !li.Fields.Contains(s.Value) )
                            continue;

                        object val = null;

                        try
                        {
                            val = li[s.Value];
                        }
                        catch
                        {
                        };

                        if( val == null )
                            continue;

                        string valstr = string.Empty;
                        switch( li.Fields[s.Value].TypeAsString.ToLower() )
                        {
                            default:
                                valstr = val.ToString();
                                break;
                            case "datetime":
                                valstr = ( (DateTime)val ).ToString(ci);
                                break;
                            case "text":
                            case "lookup":
                            case "string":
                                valstr = val.ToString();
                                break;
                            case "integer":
                                valstr = ( (int)val ).ToString();
                                break;
                            case "number":
                                valstr = ( (double)val ).ToString(ci);
                                break;
                            case "currency":
                                valstr = ( (double)val ).ToString("C", ci);
                                break;
                        };


                        sb.Append(valstr);
                    }
                    finally
                    {
                        sb.AppendLine(@"</field>");

                    }
                };
                sb.AppendLine(@"</row>");
            }
            sb.AppendLine(@"</rows>");
            sb.AppendLine(@"</splist>");

            return sb.ToString();
        }
    }
}
